﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lichtspiel;
using Lichtspiel.Display;
using Lichtspiel.Input;
using Lichtspiel.Math;
using Lichtspiel.Utility;

namespace LichtspielTests.Tests
{
    class InterpolationVisualization : LichtspielTest
    {
        private int dotCount = 200;
        private int size;
        private Image image;
        private const string OriginalTitle = "Lichtspiel InterpolationVisualization";
        private Interpolator<float>.InterpolationMethod interpolationMethod;
        private int curMethod = -1;
        private float rate = 2;
        PrimitivesDrawer drawer = new PrimitivesDrawer();

        public InterpolationVisualization()
            : base(800, 600, OriginalTitle, false) {            
        }

        protected override void Load() {
//            this.Graphics.ClearColor = Color.Black;
            image = new Image("res/whiteDot.png");

            size = Math.Min(this.Width, this.Height);
            size =(int) (size * 0.7f);

            NextMethod();
        }

        private void NextMethod() {
            curMethod = (curMethod + 1) % 13;
            switch (curMethod) {
                case 0:
                    SetInterpolationMethod(InterpolationHelper.Linear, "Linear", false);
                    break;
                case 1:
                    SetInterpolationMethod((s, e, a) => InterpolationHelper.EaseIn(s, e, a, rate), "EaseIn(" + rate + ")");
                    break;
                case 2:
                    SetInterpolationMethod((s, e, a) => InterpolationHelper.EaseOut(s, e, a, rate), "EaseOut(" + rate + ")");
                    break;
                case 3:
                    SetInterpolationMethod((s, e, a) => InterpolationHelper.EaseInOut(s, e, a, rate), "EaseInOut(" + rate + ")");
                    break;
                case 4:
                    SetInterpolationMethod((s, e, a) => InterpolationHelper.ElasticIn(s, e, a, rate / 3f), "ElasticIn(" + rate / 3f + ")");
                    break;
                case 5:
                    SetInterpolationMethod((s, e, a) => InterpolationHelper.ElasticOut(s, e, a, rate / 3f), "ElasticOut(" + rate / 3f + ")");
                    break;
                case 6:
                    SetInterpolationMethod((s, e, a) => InterpolationHelper.ElasticInOut(s, e, a, rate / 3f), "ElasticInOut(" + rate / 3f + ")");
                    break;
                case 7:
                    SetInterpolationMethod(InterpolationHelper.BounceIn, "BounceIn", false);
                    break;
                case 8:
                    SetInterpolationMethod(InterpolationHelper.BounceOut, "BounceOut", false);
                    break;
                case 9:
                    SetInterpolationMethod(InterpolationHelper.BounceInOut, "BounceInOut", false);
                    break;
                case 10:
                    SetInterpolationMethod(InterpolationHelper.BackIn, "BackIn", false);
                    break;
                case 11:
                    SetInterpolationMethod(InterpolationHelper.BackOut, "BackOut", false);
                    break;
                case 12:
                    SetInterpolationMethod(InterpolationHelper.BackInOut, "BackInOut", false);
                    break;
            }
        }

        private void ResetMethod() {
            curMethod--;
            NextMethod();
        }

        private void SetInterpolationMethod(Interpolator<float>.InterpolationMethod interpolationMethod, string name) {
            SetInterpolationMethod(interpolationMethod, name, true);
        }

        private void SetInterpolationMethod(Interpolator<float>.InterpolationMethod interpolationMethod, string name, bool showRateControls) {
            this.interpolationMethod = interpolationMethod;

            if (showRateControls)
                this.Title = OriginalTitle + " || Using Method: " + name + " (space for next, <- -> for rate)";
            else {
                this.Title = OriginalTitle + " || Using Method: " + name + " (space for next)";
            }
        }

        protected override void Unload() {
            image.Dispose();
        }

        protected override void Update(GameTime time) {
            base.Update(time);

            if(this.Keyboard.IsKeyPressed(KeyCode.Space))
                NextMethod();

            if (this.Keyboard.IsKeyDown(KeyCode.Left)) {
                rate -= (float) time.Elapsed.TotalSeconds;
                ResetMethod();
            }

            if (this.Keyboard.IsKeyDown(KeyCode.Right)) {
                rate += (float) time.Elapsed.TotalSeconds;
                ResetMethod();
            }
        }

        protected override void Render() {
            float spacing = (float) size / (dotCount-1);
            float startX = this.Width / 2f - size / 2f;
            float endY = this.Height / 2f + size / 2f;

            drawer.DrawRectangleOutline(new Rectangle((int)startX, (int)(endY - size), size, size), new Color(0.8f, 0.8f, 0.8f), 1f);


            List<Vector2> vertices = new List<Vector2>(dotCount);
            for(float x = 0; x < dotCount; x++) {
                float y = interpolationMethod.Invoke(0, dotCount - 1, x / (dotCount - 1));

                vertices.Add(new Vector2((startX + x * spacing) - image.Width / 2f, (endY - y * spacing) - image.Height / 2f));
            }

            drawer.DrawLineStrip(vertices, Color.Black, 2f);
        }
    }
}
